gusucode.com > 各种VC自绘控件源码程序 > 各种VC自绘控件源码/code/SkinControls(自绘MFC基本控件 )/SkinControls/SkinControls/SkinTreeCtrl.cpp

    
#include "stdafx.h"
#include "SkinTreeCtrl.h"
#include "MemDC.h"

//////////////////////////////////////////////////////////////////////////

IMPLEMENT_DYNAMIC(CSkinTreeCtrl, CTreeCtrl)

BEGIN_MESSAGE_MAP(CSkinTreeCtrl, CTreeCtrl)
	ON_WM_PAINT()
	ON_WM_SIZE()
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONDOWN()
	ON_WM_ERASEBKGND()
	ON_NOTIFY_REFLECT(NM_CLICK, OnNMClick)
	ON_WM_HSCROLL()
	ON_WM_VSCROLL()
	ON_WM_MOUSEWHEEL()
	ON_WM_MBUTTONUP()
	ON_NOTIFY_REFLECT(NM_DBLCLK, OnNMDblclk)
END_MESSAGE_MAP()


//////////////////////////////////////////////////////////////////////////

CSkinTreeCtrl::CSkinTreeCtrl()
{
	m_crGradient = RGB(64,154,191);
	m_crSelected = RGB(54,96,96);

	m_crNormalText = RGB(0,0,0);
	m_crSelectedText = RGB( 255, 255, 255 );

	m_crBackground = RGB(255,255,255);
	m_crLineColor = RGB(0,0,0);

	m_hItemSelect = NULL;
	m_hItemMouseMove = NULL;

	m_ptOldMouse.x	  = -1;
	m_ptOldMouse.y    = -1;
}

CSkinTreeCtrl::~CSkinTreeCtrl()
{
}

void CSkinTreeCtrl::PreSubclassWindow() 
{
	SetItemHeight(25);
	CRect rcClient;
	GetClientRect(&rcClient);
	m_HorOffset = rcClient.left;
	m_HorSize = rcClient.Width();
	m_VorOffset = rcClient.top;
	m_VorSize = rcClient.Height();

	CTreeCtrl::PreSubclassWindow();
}

void CSkinTreeCtrl::OnSize(UINT nType, int cx, int cy) 
{
	CTreeCtrl::OnSize(nType, cx, cy);

	Calculate();
}

void CSkinTreeCtrl::OnPaint() 
{
	CPaintDC dc(this); 

	CRect rcClient;
	GetClientRect(&rcClient);

	CMemDC BufferDC(&dc, &rcClient);

	BufferDC.FillSolidRect(&rcClient, m_crBackground);

	DrawItem(&BufferDC);
}

void CSkinTreeCtrl::Calculate()
{
	CRect rcClient;
	GetClientRect(&rcClient);
	SCROLLINFO scroll_info;
	if ( GetScrollInfo( SB_HORZ, &scroll_info, SIF_POS | SIF_RANGE ) )
	{
		m_HorOffset = -scroll_info.nPos;
		m_HorSize = max( scroll_info.nMax+1, rcClient.Width());
	}
	else
	{
		m_HorOffset = rcClient.left;
		m_HorSize = rcClient.Width();
	}
	if ( GetScrollInfo( SB_VERT, &scroll_info, SIF_POS | SIF_RANGE ) )
	{
		if ( scroll_info.nMin == 0 && scroll_info.nMax == 100) 
			scroll_info.nMax = 0;
		m_VorOffset = -scroll_info.nPos * GetItemHeight();
		m_VorSize = max( (scroll_info.nMax+2)*((int)GetItemHeight()+1), rcClient.Height() );
	}
	else
	{
		m_VorOffset = rcClient.top;
		m_VorSize = rcClient.Height();
	}
}

void CSkinTreeCtrl::GradientFillRect( CDC *pDC, CRect & rc, COLORREF crTopLeft, COLORREF crBottomRight, bool bVerGrad )
{
	TRIVERTEX        vert[2];
	GRADIENT_RECT    mesh;

	vert[0].x      = rc.left;
	vert[0].y      = rc.top;
	vert[0].Alpha  = 0x0000;
	vert[0].Blue   = GetBValue(crTopLeft) << 8;
	vert[0].Green  = GetGValue(crTopLeft) << 8;
	vert[0].Red    = GetRValue(crTopLeft) << 8;

	vert[1].x      = rc.right;
	vert[1].y      = rc.bottom; 
	vert[1].Alpha  = 0x0000;
	vert[1].Blue   = GetBValue(crBottomRight) << 8;
	vert[1].Green  = GetGValue(crBottomRight) << 8;
	vert[1].Red    = GetRValue(crBottomRight) << 8;

	mesh.UpperLeft  = 0;
	mesh.LowerRight = 1;

	pDC->GradientFill( vert, 2, &mesh, 1, bVerGrad ? GRADIENT_FILL_RECT_V : GRADIENT_FILL_RECT_H );
}

void CSkinTreeCtrl::DrawItem( CDC *pDC )
{
	HTREEITEM hCurrentItem = NULL, hParentItem = NULL; 
	CRect rcItem;				
	DWORD dwTreeStyle;			
	int nState = 0;					
	bool bSelected = false;		
	BOOL bHasChildren = FALSE;			

	hCurrentItem = GetFirstVisibleItem();
	if ( hCurrentItem == NULL )
		return;

	dwTreeStyle = ::GetWindowLong( m_hWnd, GWL_STYLE ); 

	do
	{
		nState = GetItemState( hCurrentItem, TVIF_STATE );
		hParentItem = GetParentItem( hCurrentItem );		 

		bHasChildren = ItemHasChildren( hCurrentItem )/* || hParentItem == NULL*/;

		bSelected = (nState & TVIS_SELECTED) && ((this == GetFocus()) || 
			(dwTreeStyle & TVS_SHOWSELALWAYS));

		if ( GetItemRect( hCurrentItem, &rcItem, TRUE ) )
		{
			CRect rcClient;
			GetClientRect(rcClient);
			if (rcItem.top >= rcClient.bottom)
			{
				break;	//不可见的时候,就不需要再绘制
			}

			CRect rect;
			rect.top = rcItem.top;
			rect.bottom = rcItem.bottom-1;
			rect.right = m_HorSize + m_HorOffset;
			rect.left = m_HorOffset;

			CPen pen(PS_SOLID, 1, m_crLineColor);
			pDC->SelectObject(&pen);
			pDC->MoveTo(rect.left,rect.bottom);
			pDC->LineTo(rect.right, rect.bottom);

			if ( bSelected )	
			{
				GradientFillRect( pDC, rect, m_crSelected, m_crSelected, FALSE );
			}
			else if ( m_hItemMouseMove == hCurrentItem )	
			{
				GradientFillRect( pDC, rect, m_crGradient, m_crGradient, FALSE );
			}

			if ( bHasChildren  )
			{	
				DrawExpand(rcItem,nState,pDC);
			}

			///////////如果ITEM不需要图片的话就直接画TEXT了,后面的那一部分就可以不要了///////////////////////////
			////绘制文本
			//DrawItemText(rcItem,hCurrentItem,bSelected,pDC);
			//////////////////////////////////////////////////////////////////////////

			//这个地方在其他地方用的话应该稍微修改一下,我这个地方就直接写的了,懒得做功能函数了
			CImageList * pImageList = NULL;
			pImageList = GetImageList(LVSIL_NORMAL);
			int nImage, nSelectedImage;
			BOOL b = GetItemImage(hCurrentItem, nImage, nSelectedImage);
			if (pImageList != NULL && b == TRUE)
			{
				pImageList->Draw(pDC, nImage, CPoint(rcItem.left, rcItem.top), ILD_TRANSPARENT);
				CRect rc = rcItem;
				rc.left = rcItem.left + 16 +2;
				//rc.right = rc.left + rcItem.Width();
				rc.right = m_HorSize;
				//绘制文本
				DrawItemText(rc,hCurrentItem,bSelected,pDC);
			}
			else
			{
				CRect rc = rcItem;
				rc.right = m_HorSize;
				//绘制文本
				DrawItemText(rc,hCurrentItem,bSelected,pDC);
			}
		}

	} while ( (hCurrentItem = GetNextVisibleItem( hCurrentItem )) != NULL );
}

void CSkinTreeCtrl::DrawExpand(CRect rcRect, int nState, CDC * pDC)
{
	CPoint point;
	point.x = rcRect.left - m_ImagePlusMinus.GetWidth()/2 - 4;
	point.y = rcRect.top + (rcRect.Height() - m_ImagePlusMinus.GetHeight())/2;
	
	if ( nState & TVIS_EXPANDED )	//展开
	{	
		m_ImagePlusMinus.Draw(pDC->m_hDC, point.x, point.y, m_ImagePlusMinus.GetWidth()/2, m_ImagePlusMinus.GetHeight(), 
			m_ImagePlusMinus.GetWidth()/2, 0, m_ImagePlusMinus.GetWidth()/2, m_ImagePlusMinus.GetHeight());
	}
	else	//收缩
	{
		m_ImagePlusMinus.Draw(pDC->m_hDC, point.x, point.y, m_ImagePlusMinus.GetWidth()/2, m_ImagePlusMinus.GetHeight(), 
			0, 0, m_ImagePlusMinus.GetWidth()/2, m_ImagePlusMinus.GetHeight());
	}
}

void CSkinTreeCtrl::DrawItemText(CRect rcRect, HTREEITEM hItem, bool bSelected,CDC * pDC)
{
	CString strText = GetItemText( hItem );

	pDC->SetBkMode(TRANSPARENT);
	UINT uFormat=DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_END_ELLIPSIS;
	CFont font;
	font.CreateFont(-12,0,0,0,400,0,0,0,134,3,2,1,2,TEXT("宋体"));
	pDC->SelectObject(&font);

	if (bSelected)
		pDC->SetTextColor(m_crSelectedText);
	else
		pDC->SetTextColor(m_crNormalText);
	pDC->DrawText(strText,&rcRect,uFormat);
}

void CSkinTreeCtrl::OnMouseMove(UINT nFlags, CPoint point) 
{
	CTreeCtrl::OnMouseMove(nFlags, point);

	m_ptOldMouse = point;
	HTREEITEM hItem = HitTest(point);
	if ( hItem != NULL && hItem != m_hItemMouseMove )
	{
		CRect rcItem;
		if (m_hItemMouseMove != NULL)
			GetItemRect(m_hItemMouseMove, &rcItem, FALSE);
		m_hItemMouseMove = hItem;
		InvalidateRect(&rcItem, FALSE);
		if (m_hItemMouseMove != NULL)
			GetItemRect(m_hItemMouseMove, &rcItem, FALSE);
		InvalidateRect(&rcItem, FALSE);
	}
}

void CSkinTreeCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
	CTreeCtrl::OnLButtonDown(nFlags, point);

	UINT uFlags = 0;
	HTREEITEM hItem = HitTest(point, &uFlags);

	if(hItem == NULL)
		return;

	SelectItem(hItem);
	if (!(uFlags & TVHT_ONITEMBUTTON))
		Expand(hItem, TVE_TOGGLE);

}

BOOL CSkinTreeCtrl::OnEraseBkgnd(CDC* pDC)
{
	return TRUE;
}

void CSkinTreeCtrl::OnNMClick(NMHDR *pNMHDR, LRESULT *pResult)
{
	Invalidate();
	*pResult = 0;
}

void CSkinTreeCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
	Invalidate();
	CTreeCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
}

void CSkinTreeCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
	Invalidate();
	CTreeCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
}

BOOL CSkinTreeCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
	Invalidate();
	return FALSE;
}

void CSkinTreeCtrl::OnMButtonUp(UINT nFlags, CPoint point)
{
	Invalidate();
	CTreeCtrl::OnMButtonUp(nFlags, point);
}

void CSkinTreeCtrl::OnNMDblclk(NMHDR *pNMHDR, LRESULT *pResult)
{
	Invalidate();
	*pResult = 0;
}

void CSkinTreeCtrl::SetPlusMinusImage(LPCTSTR pszFileName, DWORD imagetype)
{
	ASSERT(pszFileName != NULL);
	if (pszFileName == NULL) return;

	m_ImagePlusMinus.Load(pszFileName,imagetype);
}

void CSkinTreeCtrl::SetPlusMinusImage(HRSRC hRes, DWORD imagetype, HMODULE hModule)
{
	m_ImagePlusMinus.LoadResource(hRes,imagetype, hModule);
}

//////////////////////////////////////////////////////////////////////////